#ifndef __DATARECV_H__
#define __DATARECV_H__

#include <stdint.h>
#include <stdbool.h>
#include "debug.h"

/** ***************************************************************************
 * @note:数据接收类
 * @data:2019-9-11
 * @author:socbis
 * @insufficient_known:
 * */



/**
 * EXAMPLE:
 * 
 * */

/**
 * @note:定义了一个数据接受类，该类用于流数据的接受和处理，并限定处理的流数据有包头H，包
 *       长L有限可求(可根据包中的信息获取到)，和其它(数据段D和校验C等)。使用该类的逻辑如下：
 *          1.用户编写必须参数中相关函数
 *          2.创建&初始化,使用 DataReveiver_Init(),并配置必须参数
 *          4.从数据源获取数据,根据是否使用多缓存模式,选择不同的方式:
 *              > 单缓存模式: 配置完必须参数后,使用以下语句即可:
 *                  DataMan_t* dataman = this->select;
 *              > 多缓存模式: 每次接受到新的数据,要根据数据id选择数据管理器
 *                  DataMan_t* dataman = this->SelectBuf(this, id);
 *                  该函数能根据id返回不同的管理器,若未搜索到,则需要使用为该id
 *                  新建一个管理器:
 *                  dataman = this->CreateBuf(this, newid);
 *          5.调用PackParser分析数据,并注意,在使用多缓存模式时,需要在自定义的
 *              PackProcessor()函数中释放 this->select,使用以下语句
 *                  this->SelectBufFree(this);
 * @mo:监控数据
 * @packlen:当搜索到一个包头时，该值表示该包的长度
 * @headtype:当搜索到一个包头时，该值用来存储包类型
 * @select:当前使用的数据管理器
 * 
 * @manlist:数据管理器列表
 * @listlen:最大数据管理器列表长度
 * @muinx:最小的未使用的数据管理器为 manlist[muinx] 使用单缓存模式时，该值被初始化为-1
 * 
 * @p_head:该指针总是指向正在处理的包的包头
 * @p_next:该指针总是指向正在处理的包的包尾+1
 * 
 * NOTE:使用 DumppoolProcessorInit 函数初始化以下3个参数
 * @dumppool:垃圾池，用于存储错误数据(如果需要)，该过程在HeadChecker中实现
 * @poolmax:垃圾池长度上限
 * @DumppoolProcessor:错误数据处理函数
 * 
 * @Check:自定义校验函数
 * 
 * @minheadlen:最小的数据头长度
 * @IsHead:该函数由用户实现，在该函数中判断包类型并存储到packtype中，同时将p_head,p_next
 *          放到合适的位置，并计算packlen
 * @SearchHead:该函数由用户实现，当包头位置未在buf基地址base处时，向后遍历，搜索包头，返回
 *              新的包头地址
 * @PackProcessor:用户实现包处理函数，arg为自定义参数
 * */

/**
 * NOTE:packtype, 内置包类型index,自定义包index从2开始
 * */
#define     PackType_LenthIlliegal          -3
#define     PackType_Invalid                -2
#define     PackType_HalfPack               -1
#define     PackType_Json                   1

/**
 * NOTE:manlist, 缓冲区,可根据总线上的设备id来将数据收到不同的缓冲区
 * */
typedef struct {
    
    uint32_t    id;
    uint8_t*    base;
    uint32_t    buflen;
    uint32_t    readlen;
}DataMan_t;

typedef struct DataReceiver {
    
    /**
     * NOTE:用户可能需要关心 */
    struct Monitor {
        uint64_t bytescnt;
        uint64_t errcnt;
        uint64_t packcnt;
    }           mo;
    uint32_t    packlen;
    int         packtype;

    /**
     * NOTE:无论使用单缓存/多缓存模式,用户处理的数据时(PackProcessor)
     * 使用此指针即可, select->base
     * */
    DataMan_t*  select;

    /**
     * NOTE:用户无需关心 */
    DataMan_t** manlist;
    uint32_t    listlen;
    int         muinx;
    uint8_t*    p_head;
    uint8_t*    p_next;
    uint32_t    poollen;
    
    /**
     * NOTE:用户必须参数 */
    uint32_t    minheadlen;
    void        (*IsHead)(struct DataReceiver* this);
    void        (*HeadChecker)(struct DataReceiver* this, void* arg);
    void*       (*SearchHead)(const void* buf, uint32_t buflen);

    /**
     * NOTE:用户可选参数 */
    int         (*Check)(struct DataReceiver* this);
    uint8_t*    dumppool;
    uint32_t    poolmax;
    void        (*DumppoolProcessor)(struct DataReceiver* this, void* arg);

    /**
     * NOTE:类自动化函数,以下函数在类内部实现.无需用户编写 */
    uint32_t    (*PackParser)(struct DataReceiver* this, void* arg);
    DataMan_t*  (*CreateBuf)(struct DataReceiver* this, uint32_t buflen, 
                                                                uint32_t id);
    DataMan_t*  (*SelectBuf)(struct DataReceiver* this, uint32_t id);
    void        (*SelectBufFree)(struct DataReceiver* this);
    void        (*AllBufFree)(struct DataReceiver* this);
    void        (*PackProcessor)(struct DataReceiver* this, void* arg);
    
    
}DataReceiver_t;



/** 
 * @function:初始化一个在堆区或静态区创建的数据接受器 */
extern bool DataReveiver_Init(struct DataReceiver* new, uint32_t bufcnt, 
                                                    uint32_t buflen);


/**
 * @function: 初始化垃圾处理函数
 * */
void DumppoolProcessorInit(struct DataReceiver* new, uint32_t poolmax, 
                    void (*DumpProcessor)(struct DataReceiver* , void* ));


/**
 * @function:该函数初始化一个特例,JSON数据接收器
 * */
extern bool JSONRecverInit(struct DataReceiver* new, uint32_t buflen, 
                    void (*packprocessor)(struct DataReceiver* , void* ));



#define     Is_JsonHead(intial)             (*(char*)(intial) == '{' && \
                                            *((char*)intial + 1) == '"')

#endif /*  __DATARECV_H__  */
